package com.acenodie.acenodieopenglturorial.filter;

import android.content.Context;
import android.opengl.Matrix;

import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import java.util.List;

public class VideoMagicFilter {
	private static final String TAG = "VideoMagicFilter";

	private CameraInputFilter mCameraInputFilter;
	private GPUImageFilter mFilters = null;
	private GPUImageFilter mCustomizeFilter = null;
	private GPUImageFilter mCustomizeGroupFilters = null;
	private GPUImageFilterFactory mFilterFactory = null;
	private int mFilterType = GPUImageFilterType.NONE;
	private FloatBuffer mGLCubeBuffer;
	private FloatBuffer mGLTextureBuffer;
	private int mDisplayWidth = 0, mDisplayHeight = 0;
	private int mOutputWidth = 0, mOutputHeight = 0;

	public VideoMagicFilter() {
		mCameraInputFilter = new CameraInputFilter();
		mFilterFactory = new GPUImageFilterFactory("wsfilter");

		mGLCubeBuffer = ByteBuffer.allocateDirect(TextureRotationUtil.CUBE.length * 4).order(ByteOrder.nativeOrder())
				.asFloatBuffer();
		mGLCubeBuffer.put(TextureRotationUtil.CUBE).position(0);
		mGLTextureBuffer = ByteBuffer.allocateDirect(TextureRotationUtil.TEXTURE_NO_ROTATION.length * 4)
				.order(ByteOrder.nativeOrder()).asFloatBuffer();
		mGLTextureBuffer.put(TextureRotationUtil.getRotation(Rotation.NORMAL, false, true)).position(0);
	}

	public void initFilter() {
		mCameraInputFilter.init();
	}

	public int createFilter(int type, Context context) {
		mFilterType = type;
		if (mFilters != null) {
			mFilters.destroy();
			mFilters = null;
		}
		mCameraInputFilter.onOutputSizeChanged(mOutputWidth, mOutputHeight);
		if (mFilterType == GPUImageFilterType.CUSTOMIZE) {
			mFilters = mCustomizeFilter;
		} else if (mFilterType == GPUImageFilterType.CUSTOMIZEGROUP) {
			mFilters = mCustomizeGroupFilters;
		} else {
			mFilters = mFilterFactory.getFilters(mFilterType, context);
		}
		
		if (mFilters == null) {
			mFilterType = GPUImageFilterType.NONE;
			mFilters = mFilterFactory.getFilters(mFilterType, context);
		}
		
		if (mFilters != null) {
			mFilters.init();
			mFilters.onDisplaySizeChanged(mDisplayWidth, mDisplayHeight);
			mFilters.onOutputSizeChanged(mOutputWidth, mOutputHeight);
		}

		mCameraInputFilter.onDisplaySizeChanged(mDisplayWidth, mDisplayHeight);
		if (mFilters != null && !mFilters.isInitialized()) {
			return -1;
		} else {
			return 0;
		}
	}

	public void onFilterChanged(int displayWidth, int displayHeight, int outputWidth, int outputHeight) {
		if (mDisplayWidth == displayWidth && mDisplayHeight == displayHeight && mOutputWidth == outputWidth
				&& mOutputHeight == outputHeight) {
			return;
		}
		mDisplayWidth = displayWidth;
		mDisplayHeight = displayHeight;
		mOutputWidth = outputWidth;
		mOutputHeight = outputHeight;
		mCameraInputFilter.onOutputSizeChanged(mOutputWidth, mOutputHeight);
		if (mFilters != null) {
			mFilters.init();
			mFilters.onDisplaySizeChanged(mDisplayWidth, mDisplayHeight);
			mFilters.onOutputSizeChanged(mOutputWidth, mOutputHeight);
		}
		mCameraInputFilter.onDisplaySizeChanged(mDisplayWidth, mDisplayHeight);
	}

	public int onDrawFrame(final int textureId, boolean flip, final float[] transformMatrix) {
		int filterId = textureId;
		float[] matrix = transformMatrix.clone();
		if (flip) {
			filpMatrix(matrix);
		}
		mCameraInputFilter.setTextureTransformMatrix(matrix);
		filterId = mCameraInputFilter.onDrawToTexture(textureId);
		if (mFilters != null) {
			int tempId;
			tempId = mFilters.onDrawFrame(filterId, mGLCubeBuffer, mGLTextureBuffer);
			filterId = tempId;
		}
		return filterId;
	}

	public void onDrawFrame(final int textureId, final float[] transformMatrix) {
		float[] matrix = transformMatrix.clone();
		mCameraInputFilter.setTextureTransformMatrix(matrix);
		mCameraInputFilter.onDrawFrame(textureId, mGLCubeBuffer, mGLTextureBuffer);
	}

	public int getFilterType() {
		return mFilterType;
	}

	public synchronized void destroy() {
		if (mCameraInputFilter != null) {
			mCameraInputFilter.destroy();
			mCameraInputFilter = null;
		}
		
		if (mFilters != null) {
			mFilters.destroy();
			mFilters = null;
		}
		
		if (mCustomizeFilter != null) {
			mCustomizeFilter.destroy();
			mCustomizeFilter = null;
		}
		
		if (mCustomizeGroupFilters != null) {
			mCustomizeGroupFilters.destroy();
			mCustomizeGroupFilters = null;
		}
		
		if (mGLCubeBuffer != null) {
			mGLCubeBuffer.clear();
			mGLCubeBuffer = null;
		}
		
		if (mGLTextureBuffer != null) {
			mGLTextureBuffer.clear();
			mGLTextureBuffer = null;
		}
		
		mFilterFactory = null; 
	}

	private void filpMatrix(float[] matrix) {
		Matrix.translateM(matrix, 0, 0.5f, 0.5f, 0.0f);
		Matrix.scaleM(matrix, 0, 1.0f, -1.0f, 1.0f);
		Matrix.translateM(matrix, 0, -0.5f, -0.5f, 0.0f);
	}
	
	public void setFilter(GPUImageFilter filter) {
		mCustomizeFilter = filter;
	}
	
	public void setFilter(List<GPUImageFilter> filters) {
		if (filters != null) {
			mCustomizeGroupFilters = new GPUImageMultipleFilter(filters);
		}
	}

    public void setFilterLevel(int level) {
        if (mFilters != null) {
            mFilters.setLevel(level);
        }
    }
}
